/*Keyhole interface circuit. 
- Version = 3.6.2.1. Updated to be consistent with E-14 includng RAMB16.
- delayed opb_ack for reads and writes differentially.
- Changes to triggerRD[1] from triggerRd[2]
- Clocked on write instead of wrH etc. <<<< backed out.
- Changed value of reset_adr (sys_reset.v).
- Clocked pc2ppcFifo in OPB_Clk90 instead of OPB_Clk.
- Generated pc2ppc_fifo_enableWr directly.
- Passed pcmcia_cmnd back through pc2ppc_status so that PPC s/w can await msg completion.
- V3.4.0.8 passed cmnd back to pcmcia_ppc2pc_stat and pcmcia_pc2ppc_stat so that PC s/w can await msg completion.
- V3.4.0.9 six bit wide status, 6 bit wide signature in status registers.

 This module implements two 36bit FIFO's that are visible on the OPB bus and
 the PCMCIA bus. Through these FIFO's the PPC and the PC communicate. 
 The high order four bits of the 36bit data word are a software command which
 dictates what the sender expects the receiver to do with the 32bit data.

 The fifo status comprises: 0x01 = almost empty, 0x02 = full, 
                            0x04 = empty.

 ------------------ PPC -> PC fifo ----------------- Usage ----    
 OPB_PPC2PC_CMND    (PPC[0x70000000]   4bit Command  write only.
 OPB_PPC2PC_DATA    (PPC[0x70000004]   32bit data    write only.    
 OPB_PPC2PC_STAT    (PPC[0x70000008]   4bit Status   read only.
 PCMCIA_PPC2PC_CMND (pcmcia reg[0x14]) 4bit Command  read only.
 PCMCIA_PPC2PC_STAT (pcmcia reg[0x54]) 4bit Status   read only.
 PCMCIA_PPC2PC_DATA (pcmcia reg[0x1C]) 32bit data    read only.
 
 ------------------ PC -> PPC fifo ----------------- Usage ----    
 OPB_PC2PPC_CMND    (PPC[0x70000010]   4bit Command  read only.    
 OPB_PC2PPC_DATA    (PPC[0x70000014]   32bit data    read only.    
 OPB_PC2PPC_STAT    (PPC[0x70000018]   4bit Status   read only.    
 PCMCIA_PC2PPC_CMND (pcmcia reg[0x24]) 4bit Command  write only.
 PCMCIA_PC2PPC_STAT (pcmcia reg[0x5C]) 4bit Status   read only.
 PCMCIA_PC2PPC_DATA (pcmcia reg[0x2C]) 32bit data    write only.
 
Note: 
  The interface to the ppc needs two reads/writes to handle 36 bits.
      On reads:
          read status port to get determine when fifo is not empty.
          read 32bit data, this triggers a fifo read.
          read command.
      On writes:
          read status port to get determine when fifo is not almost full.
          write command. 
          write 32bit data, this triggers the fifo.
  The interface to the pcmcia needs three read/writes to handle 36 bits.
      On reads:
          read status port to determine when fifo is not empty.
          read low  order 16bits. This triggers a read from the fifo,
          read high order 16bits.
          read command.
      On writes:
          read status port to determine when fifo is not almost full.
          write command,  
          write low  order 16bits,
          write high order 16bits. This triggers a write to the fifo.
Note:
  OPB addresses are always in 32 bit mode. Since 32bit mode is used byte steering is ignored.
  In 32bit mode the lower two address lines are don't cares, thus:
  OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PPC2PC_STAT  refers to the 32bit status register.

  Author: Robert Trout, Danielle Parris.
*/

`include "PicoDefines.v"

module Keyhole(
   CFIORead, CFIOWrite, IOAddress, din, dout, test_pins,        //PCMCIA Bus signals
   OPB_Clk, OPB_Clk90, sys_rst, OPB_ABus, OPB_BE, OPB_DBus, //OPB -> Slave Signals
   OPB_RNW, OPB_select, OPB_seqAddr,
   Sl_DBus, Sl_errAck, Sl_retry, Sl_toutSup, Sl_xferAck     //Slave -> OPB Signals
);

parameter C_OPB_AWIDTH    = 32;
parameter C_OPB_DWIDTH    = 32;
parameter C_PCMCIA_DWIDTH = 16;
parameter C_PCMCIA_AWIDTH = `PCMCIA_ADR_LINES;
parameter C_BASEADDR      = `OPB_KEYHOLE_BASEADDR;
parameter C_FIFO_COUNT    = 512;
parameter C_FIFO_ADR_BITS = 9;
parameter C_ALMOST_FULL   = 8;                        //full when only 8 slots left
parameter C_ALMOST_EMPTY  = 131;                      //almost empty when less than 131 slots filed

//signatures adorn various output ports for sanity checking.
`define OPB_PC2PPC_CMND_SIGNATURE     7'h78 
`define OPB_PC2PPC_STAT_SIGNATURE     7'h3C 
`define OPB_PPC2PC_STAT_SIGNATURE     7'h1A 
`define PCMCIA_PPC2PC_CMND_SIGNATURE  7'h12
`define PCMCIA_PPC2PC_STAT_SIGNATURE  7'h23
`define PCMCIA_PC2PPC_STAT_SIGNATURE  7'h34

input  CFIORead;                        //IO Read from PCMCIA connector, DRP: 1/10/07 must read address straight from cardbus
input  CFIOWrite;                       //IO Write to  PCMCIA connector, DRP: 1/10/07 must read address straight from cardbus
input  [C_PCMCIA_AWIDTH-1:0] IOAddress;
input  [C_PCMCIA_DWIDTH-1:0] din;
output [C_PCMCIA_DWIDTH-1:0] dout;

output [127:0] test_pins;

input  OPB_Clk;                       //50 Mhz clock.
input  OPB_Clk90;                     //clock 90 degree ahead of OPB_Clk (not used)
input  sys_rst;                       //System reset
input  OPB_seqAddr;                   //nu
input  [C_OPB_AWIDTH-1:0] OPB_ABus;   //ppc address bus
input  OPB_RNW;                       //read not write
input  [C_OPB_DWIDTH-1:0] OPB_DBus;   //data from ppc bus
input  [3:0]   OPB_BE;                //ppc bus byte steering (not used)
input  [0:0]   OPB_select;            //nu
output [C_OPB_DWIDTH-1:0] Sl_DBus;    //data to ppc bus
output Sl_xferAck;                    //signals acknowledgement of read/write
output Sl_retry;
output Sl_errAck;
output Sl_toutSup;

//----------------- Bus access control lines ---------------------------------------
//----------------- PPC->PC fifo ---------------------------------------------------
wire   opb_ppc2pc_cmnd,     opb_ppc2pc_data,       opb_ppc2pc_stat;
wire   opb_ppc2pc_cmnd_wr,  opb_ppc2pc_data_wr,    opb_ppc2pc_stat_rd;
assign opb_ppc2pc_cmnd        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PPC2PC_CMND);
assign opb_ppc2pc_data        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PPC2PC_DATA);   
assign opb_ppc2pc_stat        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PPC2PC_STAT);
assign opb_ppc2pc_cmnd_wr     = (opb_ppc2pc_cmnd  & ~OPB_RNW);      // opb write cmnd
assign opb_ppc2pc_data_wr     = (opb_ppc2pc_data  & ~OPB_RNW);      // opb write data
assign opb_ppc2pc_stat_rd     = (opb_ppc2pc_stat  &  OPB_RNW);      // opb read  status

wire   pcmcia_ppc2pc_cmnd,    pcmcia_ppc2pc_dataL,    pcmcia_ppc2pc_dataH,    pcmcia_ppc2pc_statL,    pcmcia_ppc2pc_statH;
wire   pcmcia_ppc2pc_cmnd_rd, pcmcia_ppc2pc_data_rdL, pcmcia_ppc2pc_data_rdH, pcmcia_ppc2pc_stat_rdL, pcmcia_ppc2pc_stat_rdH;
assign pcmcia_ppc2pc_cmnd     = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PPC2PC_CMND);
assign pcmcia_ppc2pc_dataL    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PPC2PC_DATA);
assign pcmcia_ppc2pc_dataH    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PPC2PC_DATA+2);
assign pcmcia_ppc2pc_statL    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PPC2PC_STAT);
assign pcmcia_ppc2pc_statH    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PPC2PC_STAT+2);
assign pcmcia_ppc2pc_cmnd_rd  = (pcmcia_ppc2pc_cmnd  & CFIORead);     // pcmcia read cmnd
assign pcmcia_ppc2pc_data_rdL = (pcmcia_ppc2pc_dataL & CFIORead);     // pcmcia read low  order 16bits
assign pcmcia_ppc2pc_data_rdH = (pcmcia_ppc2pc_dataH & CFIORead);     // pcmcia read high order 16bits
assign pcmcia_ppc2pc_stat_rdL = (pcmcia_ppc2pc_statL & CFIORead);     // pcmcia read status low  order 16 bits
assign pcmcia_ppc2pc_stat_rdH = (pcmcia_ppc2pc_statH & CFIORead);     // pcmcia read status high order 16 bits

//----------------- PC->PPC fifo ---------------------------------------------------
wire   opb_pc2ppc_cmnd,     opb_pc2ppc_data,       opb_pc2ppc_stat;   
wire   opb_pc2ppc_cmnd_rd,  opb_pc2ppc_data_rd,    opb_pc2ppc_stat_rd;
assign opb_pc2ppc_cmnd        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PC2PPC_CMND);
assign opb_pc2ppc_data        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PC2PPC_DATA);   
assign opb_pc2ppc_stat        = ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0} == `OPB_PC2PPC_STAT);
assign opb_pc2ppc_cmnd_rd     = (opb_pc2ppc_cmnd & OPB_RNW);        // opb read cmnd
assign opb_pc2ppc_data_rd     = (opb_pc2ppc_data & OPB_RNW);        // opb read data
assign opb_pc2ppc_stat_rd     = (opb_pc2ppc_stat & OPB_RNW);        // opb read status

wire   pcmcia_pc2ppc_cmnd,    pcmcia_pc2ppc_dataL,    pcmcia_pc2ppc_dataH,    pcmcia_pc2ppc_statL,    pcmcia_pc2ppc_statH;
wire   pcmcia_pc2ppc_cmnd_wr, pcmcia_pc2ppc_data_wrL, pcmcia_pc2ppc_data_wrH, pcmcia_pc2ppc_stat_rdL, pcmcia_pc2ppc_stat_rdH;
assign pcmcia_pc2ppc_cmnd     = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PC2PPC_CMND);
assign pcmcia_pc2ppc_dataL    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PC2PPC_DATA);
assign pcmcia_pc2ppc_dataH    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PC2PPC_DATA+2);
assign pcmcia_pc2ppc_statL    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PC2PPC_STAT);
assign pcmcia_pc2ppc_statH    = ({IOAddress[C_PCMCIA_AWIDTH-1:1], 1'b0} == `PCMCIA_PC2PPC_STAT+2);
assign pcmcia_pc2ppc_cmnd_wr  = (pcmcia_pc2ppc_cmnd  & CFIOWrite);    // pcmcia write cmnd
assign pcmcia_pc2ppc_data_wrL = (pcmcia_pc2ppc_dataL & CFIOWrite);    // pcmcia write low  order 16bits
assign pcmcia_pc2ppc_data_wrH = (pcmcia_pc2ppc_dataH & CFIOWrite);    // pcmcia write high order 16bits
assign pcmcia_pc2ppc_stat_rdL = (pcmcia_pc2ppc_statL & CFIORead);     // pcmcia read status
assign pcmcia_pc2ppc_stat_rdH = (pcmcia_pc2ppc_statH & CFIORead);     // pcmcia read status

wire   Sl_all_writes;                                               //true for all writes from ppc
wire   Sl_all_reads;                                                //true for all reads  from ppc
assign Sl_all_writes          = opb_ppc2pc_cmnd_wr | opb_ppc2pc_data_wr;
assign Sl_all_reads           = opb_pc2ppc_cmnd_rd | opb_pc2ppc_data_rd | opb_ppc2pc_stat_rd | opb_pc2ppc_stat_rd;

reg  [C_OPB_DWIDTH-1:0]opb_dataIn;           //buffers data until written to ppc2pc_fifo.
reg  [3:0]  ppc2pc_cmndIn;                   //buffers cmnd  until written to ppc2pc_fifo.
reg  [3:0]  ppc2pc_cmndOutLatch;             //cmnd latched on data read
reg  [3:0]  pc2ppc_cmndOutLatch;             //cmnd latched on data read.
reg  [31:0] pcmcia_dataIn;                   //buffers data until written to pc2ppc_fifo. 
reg  [3:0]  pcmcia_cmndIn;                   //buffers cmnd  until written to pc2ppc_fifo.
wire [31:0] pcmcia_dataOut;                  //data out relies on registered output of ppc2pc_fifo.
wire [3:0]  pcmcia_cmndOut;                  //cmnd out relies on registered output of ppc2pc_fifo.
wire [5:0]  pc2ppc_stat;                     //status bits of pc2ppc_fifo
wire [C_OPB_DWIDTH-1:0]opb_dataOut;          //data out relies on registered output in pc2ppc_fifo. 
wire [3:0]  opb_cmndOut;                     //cmnd out relies on registered output of pc2ppc_fifo.
wire [5:0]  ppc2pc_stat;                     //status bits of ppc2pc_fifo 
wire [C_FIFO_ADR_BITS-1:0] ppc2pc_count;     //number of items in ppc2pc_fifo 
wire [C_FIFO_ADR_BITS-1:0] pc2ppc_count;     //number of items in pc2ppc_fifo

reg  pc2ppc_pcmcia_reading=0;         //stays high until read from pcmcia is complete. Synced with OPB_Clk
reg  ppc2pc_fifo_read_inhibit=0;      //Holds ppc2pc_fifo_enabledRd off until pcmcia read returns to zero.

reg  pc2ppc_pcmcia_writing=0;         //stays high until write from pcmcia is complete. Synced with OPB_Clk
reg  pc2ppc_fifo_enableWr=0;          //Signal controlling write to pc2ppc_fifo.

assign Sl_xferAck = Sl_all_writes | Sl_all_reads;
assign Sl_retry   = 0;
assign Sl_errAck  = 0;
assign Sl_toutSup = 0;

reg [C_FIFO_ADR_BITS-1:0]ppc2pc_rdAdr = 0; //adr of next item to read (ppc->pc)
reg [C_FIFO_ADR_BITS-1:0]ppc2pc_wrAdr = 0; //adr of next item to write(ppc->pc)

reg [C_FIFO_ADR_BITS-1:0]pc2ppc_rdAdr = 0; //adr of next item to read (pc->ppc)
reg [C_FIFO_ADR_BITS-1:0]pc2ppc_wrAdr = 0; //adr of next item to write(pc->ppc)
reg pc2ppc_stepRdAdr = 0;                  //signals to step read address

wire   NetFalse;
assign NetFalse = 0;
wire   NetTrue;
assign NetTrue  = 1;

//----------------- Test Pins ------------------------------------------------------
assign test_pins[31:0]    = OPB_ABus[C_OPB_AWIDTH-1:0];
assign test_pins[63:32]   = OPB_DBus[C_OPB_DWIDTH-1:0];
assign test_pins[95:64]   = Sl_DBus[C_OPB_AWIDTH-1:0];
assign test_pins[96]      = CFIOWrite;
assign test_pins[97]      = CFIORead;
assign test_pins[113:98]  = din[15:0];
assign test_pins[121:114] = IOAddress[C_PCMCIA_AWIDTH-1:0];
assign test_pins[124:122] = 3'b0;
assign test_pins[125]     = pc2ppc_fifo_enableWr;
assign test_pins[126]     = pc2ppc_pcmcia_writing;
assign test_pins[127]     = 1'b0;

//--------------------- PPC -> PC Fifo ---------------------------------------------
//The pcmcia bus has a very long read/write signal which is asynchronous with opb_clk.
//The triggering event is the read from the high order 16bit pcmcia_word.
//This logic keeps it down to one opb_clk and prevents it coming on again until CFIORead is deasserted.
always @(posedge OPB_Clk)
   begin
   if (pcmcia_ppc2pc_data_rdH & ~pc2ppc_pcmcia_reading) 
      begin
      pc2ppc_pcmcia_reading    <= 1;
      ppc2pc_fifo_read_inhibit <= 0;
      ppc2pc_cmndOutLatch      <= pcmcia_cmndOut; //latch cmndOut
      end
   else 
   if (CFIORead & pc2ppc_pcmcia_reading)
      ppc2pc_fifo_read_inhibit <= 1;
   else 
   if (~CFIORead && pc2ppc_pcmcia_reading) 
      begin
      pc2ppc_pcmcia_reading    <= 0;
      ppc2pc_fifo_read_inhibit <= 0;
      ppc2pc_rdAdr             <= ppc2pc_rdAdr + 1;
      end
   end
	
RAMB16 #
   (.DOA_REG(0),                  // Optional output pipeline registers on A port
    .DOB_REG(0),                  // Optional output pipeline registers on B port
    .INIT_A(36'h000000000),       // Initial values on A output port
    .INIT_B(36'h050505050),       // Initial values on B output port
    .INVERT_CLK_DOA_REG("FALSE"), // Invert clock on A port output registers ("TRUE" or "FALSE")
    .INVERT_CLK_DOB_REG("FALSE"), // Invert clock on B port output registers ("TRUE" or "FALSE")
    .RAM_EXTENSION_A("NONE"),     // "UPPER", "LOWER" or "NONE" when cascaded
    .RAM_EXTENSION_B("NONE"),     // "UPPER", "LOWER" or "NONE" when cascaded
    .READ_WIDTH_A(36),
    .READ_WIDTH_B(36),
//  .SIM_COLLISION_CHECK("ALL"),  // Collision check enable "ALL", "WARNING_ONLY", "GENERATE_X_ONLY" or "NONE"
    .SRVAL_A(36'h000000000),      // Set/Reset value for A port output
    .SRVAL_B(36'h0A0A0A0A0),      // Set/Reset value for B port output
    .WRITE_MODE_A("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE"
    .WRITE_MODE_B("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE"
    .WRITE_WIDTH_A(36),
    .WRITE_WIDTH_B(36) 
   )
ppc2pc_fifo (
//  .CASCADEOUTA(CASCADEOUTA),         // 1-bit cascade output
//  .CASCADEOUTB(CASCADEOUTB),         // 1-bit cascade output
//  .DOA(),                            // 32-bit A port data output
    .DOB(pcmcia_dataOut),              // 32-bit B port data output
//  .DOPA(),                           // 4-bit A port parity data output
    .DOPB(pcmcia_cmndOut),             // 4-bit B port parity data output
    .ADDRA({1'b0, ppc2pc_wrAdr, 5'b0}),// 15-bit A port address
    .ADDRB({1'b0, ppc2pc_rdAdr, 5'b0}),// 15-bit B port address
//  .CASCADEINA(CASCADEINA),           // 1-bit cascade A
//  .CASCADEINB(CASCADEINB),           // 1-bit cascade B
    .CLKA(OPB_Clk),                    // 1-bit A port clock
    .CLKB(OPB_Clk),                    // 1-bit B port clock
    .DIA(OPB_DBus),                    // 32-bit A port data
//  .DIB(DIB),                         // 32-bit B port data
    .DIPA(ppc2pc_cmndIn),              // 4-bit A port parity data
//  .DIPB(DIPB),                       // 4-bit B port parity data
    .ENA(NetTrue),                     // 1-bit A port enable
    .ENB(NetTrue),                     // 1-bit B port enable
    .REGCEA(NetFalse),                 // 1-bit A port register enable
    .REGCEB(NetFalse), //True),        // 1-bit B port register enable
    .SSRA(sys_rst),                    // 1-bit A port set/reset
    .SSRB(sys_rst),                    // 1-bit B port set/reset
    .WEA({4{opb_ppc2pc_data_wr}}),     // 4-bit A port write enable
    .WEB({4{NetFalse}})                // 4-bit B port write enable
   );
    
//Status signals: Fifo is empty when read address = write address, Full when less than two items remaining
assign ppc2pc_count   = (ppc2pc_wrAdr - ppc2pc_rdAdr);
assign ppc2pc_stat[0] = (ppc2pc_count <= C_ALMOST_EMPTY);                //almost empty
assign ppc2pc_stat[2] = (ppc2pc_count == 0);                             //empty
//Fifo is full when count is within C_ALMOST_FULL of absolutely full
assign ppc2pc_stat[1] = (ppc2pc_count >= (C_FIFO_COUNT - C_ALMOST_FULL));//almost full

//--------------------- PC -> PPC Fifo ---------------------------------------------
//Create write enable signal pc2ppc_fifo_enableWr synchronized with OPB_Clk
//The triggering event is a write to the upper 16 bits of the pcmcia_data word.
//The pcmcia bus has a very long read/write signal which is asynchronous with opb_clk.
//This logic keeps it down to one opb_clk and prevents it coming on again until write is deasserted.
always @(posedge OPB_Clk)
   begin
   if (pcmcia_pc2ppc_data_wrH & ~pc2ppc_pcmcia_writing) 
      begin
      pc2ppc_pcmcia_writing     <= 1;
      pc2ppc_fifo_enableWr      <= 1;
      end
   else 
   if (pc2ppc_fifo_enableWr)
      pc2ppc_fifo_enableWr      <= 0;
   else 
   if ((~pcmcia_pc2ppc_data_wrH | CFIORead) & pc2ppc_pcmcia_writing)
      begin
      pc2ppc_pcmcia_writing     <= 0;
      pc2ppc_wrAdr              <= pc2ppc_wrAdr + 1;
      end
   end

RAMB16 #
   (.DOA_REG(0),                  // Optional output pipeline registers on A port
    .DOB_REG(0),                  // Optional output pipeline registers on B port
    .INIT_A(36'h000000000),       // Initial values on A output port
    .INIT_B(36'h05A5A5A5A),       // Initial values on B output port
    .INVERT_CLK_DOA_REG("FALSE"), // Invert clock on A port output registers ("TRUE" or "FALSE")
    .INVERT_CLK_DOB_REG("FALSE"), // Invert clock on B port output registers ("TRUE" or "FALSE")
    .RAM_EXTENSION_A("NONE"),     // "UPPER", "LOWER" or "NONE" when cascaded
    .RAM_EXTENSION_B("NONE"),     // "UPPER", "LOWER" or "NONE" when cascaded
    .READ_WIDTH_A(36),
    .READ_WIDTH_B(36),
//  .SIM_COLLISION_CHECK("ALL"),  // Collision check enable "ALL", "WARNING_ONLY", "GENERATE_X_ONLY" or "NONE"
    .SRVAL_A(36'h000000000),      // Set/Reset value for A port output
    .SRVAL_B(36'h0A5A5A5A5),      // Set/Reset value for B port output
    .WRITE_MODE_A("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE"
    .WRITE_MODE_B("WRITE_FIRST"), // "WRITE_FIRST", "READ_FIRST", or "NO_CHANGE"
    .WRITE_WIDTH_A(36),
    .WRITE_WIDTH_B(36) 
   )
pc2ppc_fifo (
//  .CASCADEOUTA(CASCADEOUTA),         // 1-bit cascade output
//  .CASCADEOUTB(CASCADEOUTB),         // 1-bit cascade output
//  .DOA(),                            // 32-bit A port data output
    .DOB(opb_dataOut),                 // 32-bit B port data output
//  .DOPA(),                           // 4-bit A port parity data output
    .DOPB(opb_cmndOut),                // 4-bit B port parity data output
    .ADDRA({1'b0, pc2ppc_wrAdr, 5'b0}),// 15-bit A port address
    .ADDRB({1'b0, pc2ppc_rdAdr, 5'b0}),// 15-bit B port address
//  .CASCADEINA(CASCADEINA),           // 1-bit cascade A
//  .CASCADEINB(CASCADEINB),           // 1-bit cascade B
    .CLKA(OPB_Clk),                    // 1-bit B port clock
    .CLKB(OPB_Clk),                    // 1-bit A port clock
    .DIA(pcmcia_dataIn),               // 32-bit A port data from pcmcia
//  .DIB(DIB),                         // 32-bit B port data
    .DIPA(pcmcia_cmndIn),              // 4-bit A port cmnd from pcmcia
//  .DIPB(DIPB),                       // 4-bit B port parity data
    .ENA(NetTrue),                     // 1-bit A port enable
    .ENB(NetTrue),                     // 1-bit B port enable
    .REGCEA(NetFalse),                 // 1-bit A port register enable
    .REGCEB(NetFalse), //True),        // 1-bit B port register enable
    .SSRA(sys_rst),                    // 1-bit A port set/reset
    .SSRB(sys_rst),                    // 1-bit B port set/reset
    .WEA({4{pc2ppc_fifo_enableWr}}),   // 4-bit A port write enable
    .WEB({4{NetFalse}})                // 4-bit B port write enable
   );

//Status signals: Fifo is empty when read address = write address
assign pc2ppc_count   = (pc2ppc_wrAdr - pc2ppc_rdAdr);
assign pc2ppc_stat[0] = (pc2ppc_count <= C_ALMOST_EMPTY);                //almost empty
assign pc2ppc_stat[2] = (pc2ppc_count == 0);                             //empty
//Fifo is full when read address = (write address+1)
assign pc2ppc_stat[1] = (pc2ppc_count >= (C_FIFO_COUNT - C_ALMOST_FULL));//almost full

always @(posedge pcmcia_pc2ppc_cmnd_wr)  pcmcia_cmndIn[3:0]                 <= din[3:0];
always @(posedge pcmcia_pc2ppc_data_wrL) pcmcia_dataIn[C_PCMCIA_DWIDTH-1:0] <= din[C_PCMCIA_DWIDTH-1:0];
always @(posedge pcmcia_pc2ppc_data_wrH) pcmcia_dataIn[31:C_PCMCIA_DWIDTH]  <= din[C_PCMCIA_DWIDTH-1:0]; 

//pcmcia read.
assign dout[C_PCMCIA_DWIDTH-1:0] = 
    (pcmcia_ppc2pc_data_rdL ?  pcmcia_dataOut[C_PCMCIA_DWIDTH-1:0]                         : 0) |
    (pcmcia_ppc2pc_data_rdH ?  pcmcia_dataOut[31:C_PCMCIA_DWIDTH]                          : 0) |
    (pcmcia_ppc2pc_cmnd_rd  ? {`PCMCIA_PPC2PC_CMND_SIGNATURE, 5'b0,   ppc2pc_cmndOutLatch} : 0) | //7'h12
    (pcmcia_ppc2pc_stat_rdL ? {ppc2pc_count[8:0], ppc2pc_cmndIn[3:0], ppc2pc_stat[2:0]   } : 0) |
    (pcmcia_ppc2pc_stat_rdH ? {`PCMCIA_PPC2PC_STAT_SIGNATURE,         ppc2pc_rdAdr[8:0]  } : 0) | //7'h23
    (pcmcia_pc2ppc_stat_rdL ? {pc2ppc_count[8:0],             4'b0,   pc2ppc_stat[2:0]   } : 0) |
    (pcmcia_pc2ppc_stat_rdH ? {`PCMCIA_PC2PPC_STAT_SIGNATURE,         pc2ppc_rdAdr[8:0]  } : 0);  //7'h34
										  
//read of pc2ppc_fifo. Data read latches command and steps fifo RdAdr on next clock.
always @(posedge OPB_Clk)
  begin
  if (opb_pc2ppc_data_rd) 
      begin
      pc2ppc_stepRdAdr    <= 1;
      pc2ppc_cmndOutLatch <= opb_cmndOut; //latch command
      end
  else
      begin
      pc2ppc_rdAdr     <= pc2ppc_rdAdr + pc2ppc_stepRdAdr;
      pc2ppc_stepRdAdr <= 0;
      end
  end

//ppc read.
assign Sl_DBus[C_OPB_DWIDTH-1:0] = 
    (opb_pc2ppc_data_rd) ?  opb_dataOut                                                                                      :
    (opb_pc2ppc_cmnd_rd) ? {`OPB_PC2PPC_CMND_SIGNATURE, 9'b0,         9'b0,              3'b0,          pc2ppc_cmndOutLatch} : //0x78
    (opb_ppc2pc_stat_rd) ? {`OPB_PPC2PC_STAT_SIGNATURE, ppc2pc_rdAdr, ppc2pc_count[8:0], 4'b0,          ppc2pc_stat[2:0]   } : //0x1A 
    (opb_pc2ppc_stat_rd) ? {`OPB_PC2PPC_STAT_SIGNATURE, pc2ppc_rdAdr, pc2ppc_count[8:0], pcmcia_cmndIn, pc2ppc_stat[2:0]  }  : //0x3C
                            32'b0;

//write to ppc2pc_fifo. Capture cmnd, write increments address.
always @(posedge OPB_Clk)
   if (~OPB_RNW)
     case ({OPB_ABus[C_OPB_AWIDTH-1:2], 2'b0})
       `OPB_PPC2PC_DATA: 
            begin
            opb_dataIn[C_OPB_DWIDTH-1:0] <= OPB_DBus[C_OPB_DWIDTH-1:0];
            ppc2pc_wrAdr                 <= ppc2pc_wrAdr+1;
            end
       `OPB_PPC2PC_CMND: 
            ppc2pc_cmndIn[3:0]           <= OPB_DBus[3:0];
     endcase
endmodule